home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- #
- # Macintosh Developer Technical Support
- #
- # Sample Control Panel Device and INIT Combination
- #
- # Program: INIT - CDEV
- # File: CDEV.c - C Source
- #
- # Copyright © 1990 Apple Computer, Inc.
- # All rights reserved.
- #
- ------------------------------------------------------------------------------*/
-
- #include <Common.h>
-
- #include <Quickdraw.h>
- #include <Files.h>
- #include <Memory.h>
- #include <OSUtils.h>
- #include <TextEdit.h>
- #include <Devices.h>
- #include <Dialogs.h>
- #include <Packages.h>
- #include <TextUtils.h>
-
- /*------------------------------------------------------------------------------
- Constants
- ------------------------------------------------------------------------------*/
-
- #define kNoINIT -4048 /* Alert: INIT was not installed */
- #define kCantWritePrefs -4047 /* Alert: error writing preferences */
-
- #define kAboutText1 1
- #define kAboutText2 2
- #define kPrompt1 3
- #define kPrompt2 4
- #define kTimesToBeep 5 /* First editTExt item in cdev */
- #define kBeepInterval 6
-
-
- /*------------------------------------------------------------------------------
- Types
- ------------------------------------------------------------------------------*/
-
- typedef struct CDEVRec {
- CommonGlobalsPtr commonGlobals;
- } CDEVRec, *CDEVPtr, **CDEVHnd;
-
-
- /*------------------------------------------------------------------------------
- Procedure Prototypes and External Routines
- ------------------------------------------------------------------------------*/
-
- /* These procedures are from the orginal EditTextCDEV sample. */
-
- pascal long TextCDEV(short message, short item, short numItems,
- short CPanelID, EventRecord *theEvent,
- Handle cdevStorage, DialogPtr CPDialog);
- void DoEditCommand(short message, DialogPtr CPDialog);
-
- /* Added for INIT - CDEV combo. */
-
- void InitEditValues(CDEVHnd cdevStorage, short numItems,
- DialogPtr CPDialog);
- void UpdateINIT(CDEVHnd cdevStorage, short numItems,
- DialogPtr CPDialog);
- void UpdatePrefs(CDEVHnd cdevStorage);
- long GetItemValue(short itemNumber, DialogPtr CPDialog);
- void SetItemValue(short itemNumber, DialogPtr CPDialog, long value);
- void GetCommonStorage(CommonGlobalsPtr *commonGlobals);
- OSErr OpenAPort(short *refNum);
- pascal void StartCompProc(PPCParamBlockPtr ppb);
-
-
- /*------------------------------------------------------------------------------
-
- pascal long TextCDEV(short message, short item, short numItems,
- short CPanelID, EventRecord *theEvent,
- Handle cdevStorage, DialogPtr CPDialog);
-
- This is the main dispatcher. It must be the first code in the cdev.
- EditCdev’s dispatcher responds only to the following messages from the
- Control Panel:
-
- macDev - To indicate what machines it is available on.
- initDev - To set up some temporary storage and get the caret started.
- keyEvtDev - To check for an edit command and do the appropriate action.
- cutDev - To cut the current selection.
- copyDev - To copy the current selection.
- pasteDev - To paste the contents of the clipboard.
- clearDev - To delete the current selection.
- closeDev - To dispose of any data allocated in initDev.
-
- The Dialog Manager’s services are used to handle entry of text, selection
- of text, editing of text, and moving between the editText items via the
- tab key. Since the Dialog Manager handles the selection of text, we do not
- have to be concerned with hitDev messages for the editText items. The only
- things we have to take care of are calling the Dialog Manager editing
- routines in response to an edit command, and getting the caret to show up
- at the beginning. In response to an edit command that was the result of a
- command-key equivalent, we must also eliminate the event so that it does
- not get processed as a keyDown by the Dialog Manager. Otherwise, an ‘x’
- would show up in the editText item when the user did a command-x to cut
- the text.
-
- ------------------------------------------------------------------------------*/
-
- pascal long TextCDEV(short message, short item, short numItems, short CPanelID,
- EventRecord *theEvent, Handle cdevStorage, DialogPtr CPDialog)
- {
- #pragma unused (item, CPanelID) /* unused formal parameters */
-
- char tempChar;
- CommonGlobalsPtr commonGlobals;
- long result;
-
- if (message == macDev) {
- if (Gestalt(gestaltPPCToolboxAttr, &result))
- return(0); /* No PPCToolbox; hide me */
- else
- return(1); /* Have PPCToolBox; show me */
- }
- else if (cdevStorage != nil) {
- switch (message) {
-
- case initDev:
- GetCommonStorage(&commonGlobals);
- if (commonGlobals) {
- /* create private storage */
- cdevStorage = NewHandle(sizeof(CDEVRec));
- if (cdevStorage) {
- (**(CDEVHnd)cdevStorage).commonGlobals = commonGlobals;
- InitEditValues( (CDEVHnd) cdevStorage, numItems, CPDialog);
- /* make caret show up */
- SelectDialogItemText(CPDialog, numItems + kTimesToBeep, 0, 999);
- }
- } else {
- (void) StopAlert(kNoINIT, (ModalFilterProcPtr) nil);
- return(cdevGenErr);
- }
- break;
-
- case closeDev: /* clean up and dispose */
- UpdateINIT((CDEVHnd) cdevStorage, numItems, CPDialog);
- UpdatePrefs((CDEVHnd) cdevStorage);
- DisposeHandle(cdevStorage);
- break;
-
- case hitDev: /* handle hit on item */
- case nulDev:
- case updateDev: /* handle any update drawing */
- case activDev: /* activate any needed items */
- case deactivDev: /* deactivate any needed items */
- break;
-
- case keyEvtDev: /* respond to keydown */
- tempChar = theEvent->message & charCodeMask;/* get the character, and check */
- if (theEvent->modifiers & cmdKey) { /* status of command key */
- message = nulDev; /* start with no message */
- theEvent->what = nullEvent; /* and empty event type */
-
- switch (tempChar) { /* set appropriate message */
-
- case 'X':
- case 'x':
- message = cutDev;
- break;
- case 'C':
- case 'c':
- message = copyDev;
- break;
- case 'V':
- case 'v':
- message = pasteDev;
- break;
- }
- DoEditCommand(message, CPDialog); /* Let edit command handler take it */
- }
- break;
-
- case macDev:
- case undoDev:
- break;
-
- case cutDev:
- case copyDev:
- case pasteDev:
- case clearDev:
- DoEditCommand(message, CPDialog); /* respond to edit command */
- break;
- }
-
- return ((long) cdevStorage);
- } /* cdevStorage != nil */
-
- /*
- ** We get here iff cdevStorage = NIL. Return 0 so that Control Panel
- ** will put up "out of memory" error
- */
- return (0);
- }
-
-
- /*------------------------------------------------------------------------------
-
- void DoEditCommand (short message, DialogPtr CPDialog)
-
- Call the appropriate Dialog Manager routine to handle an edit command for
- an editText item. It will do all the work regarding the TEScrap.
-
- ------------------------------------------------------------------------------*/
-
- void DoEditCommand (short message, DialogPtr CPDialog)
- {
- switch (message) {
- case cutDev:
- DialogCut(CPDialog);
- break;
- case copyDev:
- DialogCopy(CPDialog);
- break;
- case pasteDev:
- DialogPaste(CPDialog);
- break;
- case clearDev:
- DialogDelete(CPDialog);
- break;
- }
- }
-
-
- /*------------------------------------------------------------------------------
-
- void InitEditValues(CDEVHnd cdevStorage, short numItems, DialogPtr CPDialog)
-
- Called when the CDEV is opened. It uses the pointer to the public globals
- that we got from the INIT to get the values to stuff into the EditText
- items.
-
- ------------------------------------------------------------------------------*/
-
- void InitEditValues (CDEVHnd cdevStorage, short numItems, DialogPtr CPDialog)
- {
- CommonGlobalsPtr commonGlobals;
-
- commonGlobals = (**cdevStorage).commonGlobals;
- SetItemValue(numItems + kTimesToBeep, /* item to set */
- CPDialog, /* of this dialog */
- commonGlobals->timesToBeep); /* set to this value */
- SetItemValue(numItems + kBeepInterval, /* item to set */
- CPDialog, /* of this dialog */
- commonGlobals->beepInterval / 60); /* set to this value */
- }
-
-
- /*------------------------------------------------------------------------------
-
- void UpdateINIT(CDEVHnd cdevStorage, short numItems, DialogPtr CPDialog)
-
- Called when the CDEV is about to close. It gets the values from the
- EditText items and stuffs them back into the INIT's public globals.
-
- ------------------------------------------------------------------------------*/
-
- void UpdateINIT (CDEVHnd cdevStorage, short numItems, DialogPtr CPDialog)
- {
- CommonGlobalsPtr commonGlobals;
-
- commonGlobals = (**cdevStorage).commonGlobals;
- commonGlobals->timesToBeep = GetItemValue(numItems + kTimesToBeep, CPDialog);
- commonGlobals->beepInterval = GetItemValue(numItems + kBeepInterval, CPDialog) * 60;
- }
-
-
- /*------------------------------------------------------------------------------
-
- void UpdatePrefs(CDEVHnd cdevStorage)
-
- Called when the CDEV is being closed. This routine writes to a preferences
- file, using the INIT's public globals as the output buffer. The data is
- written to the data fork; no resources are used at all. If the preferences
- file doesn't exist, it is created. Any errors are reported through an
- Alert saying that error number such-and-such occured.
-
- ------------------------------------------------------------------------------*/
-
- void UpdatePrefs(CDEVHnd cdevStorage)
- {
- OSErr err;
- FSSpec spec;
- short refNum;
- long amountToWrite;
- Str255 errString;
-
- err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
- &spec.vRefNum, &spec.parID);
- if (err == noErr) {
- (void) PLstrcpy(spec.name, kPrefsFileName);
- err = FSpCreate(&spec, kCreator, kDocKind, smSystemScript);
- if ((err == noErr) || (err == dupFNErr)) {
- err = FSpOpenDF(&spec, fsRdWrPerm, &refNum);
- if (err == noErr) {
- amountToWrite = sizeof(CommonGlobalsRec);
- err = FSWrite(refNum, &amountToWrite,
- (Ptr) (**cdevStorage).commonGlobals);
- (void) FSClose(refNum);
- }
- }
- }
-
- if (err) {
- NumToString(err, errString);
- ParamText(errString, nil, nil, nil);
- (void) StopAlert(kCantWritePrefs, (ModalFilterProcPtr) nil);
- }
- }
-
-
- /*------------------------------------------------------------------------------
-
- long GetItemValue(short itemNumber, DialogPtr CPDialog)
-
- Utility routine used to turn the text in an EditText item into a long,
- and return it.
-
- ------------------------------------------------------------------------------*/
-
- long GetItemValue(short itemNumber, DialogPtr CPDialog)
- {
- short itemType;
- Handle itemHandle;
- Rect itemRect;
- Str255 text;
- long theNum;
-
- GetDialogItem(CPDialog, itemNumber, &itemType, &itemHandle, &itemRect);
- GetDialogItemText(itemHandle, text);
- StringToNum(text, &theNum);
- return(theNum);
- }
-
-
- /*------------------------------------------------------------------------------
-
- void SetItemValue(short itemNumber, DialogPtr CPDialog, long value)
-
- Utility routine used to turn a short into text, and stuff it into
- an EditText item
-
- ------------------------------------------------------------------------------*/
-
- void SetItemValue(short itemNumber, DialogPtr CPDialog, long value)
- {
- short itemType;
- Handle itemHandle;
- Rect itemRect;
- Str255 text;
-
- NumToString(value, text);
- GetDialogItem(CPDialog, itemNumber, &itemType, &itemHandle, &itemRect);
- SetDialogItemText(itemHandle, text);
- }
-
-
- /*------------------------------------------------------------------------------
-
- void GetCommonStorage(CommonGlobalsPtr *commonGlobals)
-
- This routine is called when the CDEV is opend to get a pointer to the
- INIT's public globals. During the life of the INIT, this pointer is saved
- in a block referenced by a handle. This handle is saved for us by the
- Control Panel.
-
- We get the pointer to the INIT's public globals by using the PPCToolbox.
- Because we wrote the INIT, we know that it is identifying itself to us by
- creator/type. So we fill out a portName with that information, and make an
- asynchronous PPCStart call. We make the call asynchronously so that the
- PPCToolbox can go an process all of the subsequent Read/Write/
- End/Inform/etc. calls required in a PPC transaction. However, we have to
- hang around for the PPCStart call to finish, so we poll ioResult until it
- no longer equal 1 (ioResult = 1 is the international symbol for "I'm
- working on a task right now, come back later when I'm done.").
-
- When the PPCStart call completes, this means that the completion routine
- we installed, StartCompProc, has been called by the PPCToolbox. It is
- StartCompProc that was responsible for reading the data being sent to us
- by the INIT. Therefore, when PPCStart completes, our data buffer should
- have the location of the INIT's public globals.
-
- ------------------------------------------------------------------------------*/
-
- void GetCommonStorage(CommonGlobalsPtr *commonGlobals)
- {
- OSErr err;
- SessionRecord sessionRecord;
- short refNum;
-
- *commonGlobals = nil;
-
- err = OpenAPort(&refNum);
- if (err) return;
-
- sessionRecord.portName.nameScript = GetScriptManagerVariable(smSysScript);
- (void) PLstrcpy(sessionRecord.portName.name, "\pBG Beeper");
- sessionRecord.portName.portKindSelector = ppcByCreatorAndType;
- #if GENERATING68K
- // Universal Interfaces 2.0
- sessionRecord.portName.u.port.portCreator = kCreator;
- sessionRecord.portName.u.port.portType = 'INIT';
- #else
- sessionRecord.portName.u.port.creator = kCreator;
- sessionRecord.portName.u.port.type = 'INIT';
- #endif
- sessionRecord.pb.startParam.ioCompletion = (PPCCompProcPtr) StartCompProc;
- sessionRecord.pb.startParam.portRefNum = refNum;
- sessionRecord.pb.startParam.serviceType = ppcServiceRealTime;
- sessionRecord.pb.startParam.resFlag = 0;
- sessionRecord.pb.startParam.portName = &sessionRecord.portName;
- sessionRecord.pb.startParam.locationName = nil;
- sessionRecord.pb.startParam.userData = kGetCommonGlobalsPtr;
- sessionRecord.pb.startParam.userRefNum = 0; /* guest access? */
-
- err = PPCStartAsync(&sessionRecord.pb.startParam);
-
- /* Even though we make an asynchronous call, we have to wait
- around for the call to complete. One reason for this is because
- we can't really do anything until we get the information we are
- asking for from the INIT. Another good reason is because our
- parameter block is allocated on the stack. If we were to leave
- now, our parameter block would vanish in a puff of orange smoke,
- along with the rest of the Operating System... */
-
- while (sessionRecord.pb.startParam.ioResult == 1) ; /* wait for the reply */
-
- if (sessionRecord.pb.startParam.ioResult == noErr)
- *commonGlobals =
- ((GetCommonGlobalsPtr) &sessionRecord.buffer)->commonGlobalsAddress;
-
- err = PPCEnd(&sessionRecord.pb.endParam, false);
- err = PPCClose(&sessionRecord.pb.closeParam, false);
- }
-
-
- /*------------------------------------------------------------------------------
-
- OSErr OpenAPort(short *refNum)
-
- Used to open a PPC port. We identify ourselves using the portName record.
- First, we give ourselves a name that will show up in the PPCBrowser
- (portName.name). We then give ourselves an identify to other processes. We
- can do this either by name or by creator/type signatures. In our case, we
- choose creator/type ('INCD'/'CDEV').
-
- We then set up for a PPCOpen call. We are making a synchronous call, so we
- don't need a completion routine. ServiceType and resFlag are set to
- required values (per Inside Mac). We make the CDEV not visible over the
- network. Next, we point to the name record we want to use for our port,
- and use the default location name (which identifies our computer to other
- computers on the network).
-
- Finally, we make the PPCOpen call synchronously, and return any errors.
-
- ------------------------------------------------------------------------------*/
-
- OSErr OpenAPort(short *refNum)
- {
- PPCPortRec thePort;
- PPCOpenPBRec pb;
- OSErr err;
-
- thePort.nameScript = GetScriptManagerVariable(smSysScript);
- (void) PLstrcpy(thePort.name, "\pBG Beeper");
- thePort.portKindSelector = ppcByCreatorAndType;
- #if GENERATING68K
- // Universal Interfaces 2.0
- thePort.u.port.portCreator = kCreator;
- thePort.u.port.portType = 'CDEV';
- #else
- thePort.u.port.creator = kCreator;
- thePort.u.port.type = 'CDEV';
- #endif
-
- pb.ioCompletion = nil;
- pb.serviceType = ppcServiceRealTime;
- pb.resFlag = 0;
- pb.networkVisible = true;
- pb.portName = &thePort;
- pb.locationName = nil; // use the default location
-
- err = PPCOpen(&pb, false);
- if (err) return(err);
-
- *refNum = pb.portRefNum;
- return(noErr);
- }
-
-
- /*------------------------------------------------------------------------------
-
- pascal void StartCompProc(PPCParamBlockPtr ppb)
-
- When the PPCStart call we made in GetCommonStorage completes, the
- PPCToolbox calls the completion routine we specified (this routine). At
- this point, our INIT has been contacted, because it had an outstanding
- PPCInform call. The INIT's PPCInform completion routine looked at what we
- stuffed in the userData field when we made the PPCStart call, and wrote
- back to us the location of its public globals with PPCWrite. Therefore, we
- have to set ourselves up to read that data with PPCRead. That's what we do
- here.
-
- Because this is a completion routine, it is declared as using the Pascal
- calling convention.
-
- ------------------------------------------------------------------------------*/
-
- pascal void StartCompProc(PPCParamBlockPtr ppb)
- {
- OSErr err;
- GetCommonGlobalsPtr myBuffer;
-
- myBuffer = (GetCommonGlobalsPtr) ((SessionPtr)ppb)->buffer;
-
- ppb->readParam.ioCompletion = nil;
- ppb->readParam.bufferLength = sizeof(GetCommonGlobalsRecord);
- ppb->readParam.bufferPtr = (Ptr) myBuffer;
- ppb->readParam.more = false;
-
- err = PPCReadAsync(&ppb->readParam);
- }
-